package com.taysear.parcel;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.taysear.parcel.domain.Loadingsheet;
import com.taysear.parcel.domain.Parcel;
import com.taysear.parcel.domain.ParcelHistory;
import com.taysear.parcel.itext.table.PdfPCell;
import com.vaadin.terminal.StreamResource.StreamSource;

/**
 * This class creates a PDF with the iText library. This class implements
 * the StreamSource interface which defines the getStream method.
 */
public class Pdf implements StreamSource {
    private final ByteArrayOutputStream os = new ByteArrayOutputStream();

    public Pdf(ParcelApplication app, Parcel parcel) {
        Document document = null;

        try {
            document = new Document(PageSize.A4, 20, 20, 50, 50);
            PdfWriter.getInstance(document, os);
            document.open();

            document.add(createParcelPrintOut(app, parcel));            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }
    
    public Pdf(ParcelApplication app, Loadingsheet loadingsheet) {
        Document document = null;

        try {
            document = new Document(PageSize.A4, 2, 2, 3, 3);
            PdfWriter.getInstance(document, os);
            document.open();

            document.add(createLoadingsheetTable(app, loadingsheet));
            document.add(new Paragraph("             "));
            String query = "SELECT p FROM Parcel p Where p.loadingsheet.loadingsheetId = " + loadingsheet.getLoadingsheetId();
            List<Parcel> parcels = app.em.createQuery(query).getResultList();
            document.add(createLoadingsheetParcelsTable(app, loadingsheet, parcels));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }

    @Override
    public InputStream getStream() {
        // Here we return the pdf contents as a byte-array
        return new ByteArrayInputStream(os.toByteArray());
    }
    
    /**
     * Creates Parcel Printout table
     * @return Parcel Printout table
     */
    public static PdfPTable createParcelPrintOut(ParcelApplication app, Parcel parcel) {
    	
        PdfPTable table = new PdfPTable(4);
        
        String senderSubstation = parcel.getParcelDetail().getSenderSubstation().getName();
        PdfPCell top = new PdfPCell("BRACH: " + senderSubstation);
        top.setBorder(0);
        top.setHorizontalAlignment(Element.ALIGN_CENTER);
        top.setColspan(4);
        table.addCell(top);
        
        PdfPCell waybillNoLabel = new PdfPCell("Waybill No:");
        waybillNoLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        waybillNoLabel.setBorderWidthRight(0f);
        table.addCell(waybillNoLabel);
        PdfPCell waybillNo = createCellWithoutBorderRightLeft(parcel.getWaybillNumber(), true);
        table.addCell(waybillNo);
        
        PdfPCell dateLabel = createCellWithoutBorderRightLeft("Date:");
        dateLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(dateLabel);
        String d = app.formatDateWithoutTime(parcel.getDate());
        PdfPCell date = new PdfPCell(d, true);
        date.setBorderWidthLeft(0f);
        table.addCell(date);
        
        PdfPCell senderLabel = createCellWithBorderLeft("Sender:");
        senderLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(senderLabel);
        PdfPCell sender = createCellWithBorderLeft(parcel.getParcelDetail().getSenderName(), true);
        sender.setBorder(0);
        table.addCell(sender);
        
        PdfPCell receiverLabel = new PdfPCell("Receiver:");
        receiverLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        receiverLabel.setBorder(0);
        table.addCell(receiverLabel);
        PdfPCell receiver = createCellWithBorderRight(parcel.getParcelDetail().getReceiverName(), true);
        table.addCell(receiver);
        
        PdfPCell originLabel = createCellWithBorderLeft("Origin:");
        originLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(originLabel);
        PdfPCell origin = createCellWithBorderLeft(parcel.getParcelDetail().getSenderStation().getName(), true);
        origin.setBorder(0);
        table.addCell(origin);
        
        PdfPCell destinationLabel = new PdfPCell("Destination:");
        destinationLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        destinationLabel.setBorder(0);
        table.addCell(destinationLabel);
        PdfPCell destination = createCellWithBorderRight(parcel.getParcelDetail().getReceiverStation().getName(), true);
        table.addCell(destination);
        
        PdfPCell senderTelLabel = createCellWithBorderLeft("Sender tel:");
        senderTelLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(senderTelLabel);
        PdfPCell senderTel = createCellWithBorderLeft(parcel.getParcelDetail().getSenderTel(), true);
        senderTel.setBorder(0);
        table.addCell(senderTel);
        
        PdfPCell receiverTelLabel = new PdfPCell("Receiver tel:");
        receiverTelLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        receiverTelLabel.setBorder(0);
        table.addCell(receiverTelLabel);
        PdfPCell receiverTel = createCellWithBorderRight(parcel.getParcelDetail().getReceiverTel(), true);
        table.addCell(receiverTel);
        
        PdfPCell quantityLabel = createCellWithBorderLeft("Quantity:");
        quantityLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(quantityLabel);
        PdfPCell quantity = createCellWithBorderLeft(parcel.getQuantity().toString(), true);
        quantity.setBorder(0);
        table.addCell(quantity);
        
        PdfPCell weightLabel = new PdfPCell("Weight:");
        weightLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        weightLabel.setBorder(0);
        table.addCell(weightLabel);
        PdfPCell weight = createCellWithBorderRight(parcel.getWeight().toString(), true);
        table.addCell(weight);
        
        PdfPCell typeLabel = createCellWithBorderLeft("Type:");
        typeLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(typeLabel);
        PdfPCell type = createCellWithBorderLeft(parcel.getParcelType().getDescription(), true);
        type.setBorder(0);
        table.addCell(type);
        
        PdfPCell amountLabel = new PdfPCell("Amount:");
        amountLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        amountLabel.setBorder(0);
        table.addCell(amountLabel);
        PdfPCell amount = createCellWithBorderRight(parcel.getAmount().toString(), true, true);
        table.addCell(amount);
        
        PdfPCell paymentModeLabel = createCellWithBorderLeft("Payment mode:");
        paymentModeLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(paymentModeLabel);
        PdfPCell paymentMode = createCellWithBorderLeft(parcel.getPaymentMode().getDescription(), true);
        paymentMode.setBorder(0);
        table.addCell(paymentMode);
        
        PdfPCell vatLabel = new PdfPCell("V.A.T:");
        vatLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        vatLabel.setBorder(0);
        table.addCell(vatLabel);
        PdfPCell vat = createCellWithBorderRight(parcel.getVatable() ? parcel.getVatAmount().toString() : "0", true, true);
        table.addCell(vat);
        
        String signHere = "_ _ _ _ _ _ _ _ _ _ _ _ _";
        PdfPCell senderSignatureLabel = createCellWithBorderLeft("Sender\nsignature:");
        senderSignatureLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(senderSignatureLabel);
        PdfPCell senderSignature = createCellWithBorderLeft(signHere);
        senderSignature.setBorder(0);
        senderSignature.setVerticalAlignment(Element.ALIGN_BOTTOM);
        table.addCell(senderSignature);
        
        PdfPCell receiverSignatureLabel = new PdfPCell("Receiver\nsignature:");
        receiverSignatureLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        receiverSignatureLabel.setBorder(0);
        table.addCell(receiverSignatureLabel);
        PdfPCell receiverSignature = createCellWithBorderRight(signHere);
        receiverSignature.setVerticalAlignment(Element.ALIGN_BOTTOM);
        table.addCell(receiverSignature);
        
        PdfPCell bottomLeft = createCellWithBorderLeftAndButtom("Read, authorised & agreed to condititions of carriage.");
        bottomLeft.setColspan(2);
        table.addCell(bottomLeft);
        
        PdfPCell bottomRight = createCellWithBorderRightAndButtom("(Above goods received in good conditions)");
        bottomRight.setColspan(2);
        bottomRight.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(bottomRight);
        
        List<ParcelHistory> list = parcel.getParcelHistories();
        ParcelHistory history = list.iterator().next();
        String servedBy = "Served by: "+history.getUser().getEmployee() + " Printed on " +
        		"" + app.formatDate(history.getDate()) +" at " +senderSubstation+" office.";
        PdfPCell bottom = new PdfPCell(servedBy, 9);
        bottom.setBorder(0);
        bottom.setHorizontalAlignment(Element.ALIGN_CENTER);
        bottom.setColspan(4);
        table.addCell(bottom);
        
        return table;
    }
    
    /**
     * Creates header table for the loadingsheet printout
     * @return header table 
     */
    public static PdfPTable createLoadingsheetTable(ParcelApplication app, Loadingsheet loadingsheet) {
        PdfPTable table = new PdfPTable(4);
        
        Phrase phrase = new Phrase("CROWN COURIER LOADING SHEET REPORT", FontFactory.getFont(FontFactory.TIMES_BOLD, 10, Font.UNDERLINE));
        PdfPCell top = new PdfPCell(phrase);
        top.setColspan(4);
        top.setHorizontalAlignment(Element.ALIGN_CENTER);
        top.setBorder(0);
        table.addCell(top);
        
        PdfPCell loadingsheetNoLabel = createCellNoBorder("Loadingsheet No:", true);
        loadingsheetNoLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(loadingsheetNoLabel);
        table.addCell(createCellNoBorder(loadingsheet.getLoadingsheetId().toString()));
        
        PdfPCell fromLabel = createCellNoBorder("From:", true);
        fromLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(fromLabel);
        table.addCell(createCellNoBorder(loadingsheet.getOrigin().getName()));        
        
        
        PdfPCell regNoLabel = createCellNoBorder("Reg No:", true);
        regNoLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(regNoLabel);
        table.addCell(createCellNoBorder(loadingsheet.getBus().getRegistrationNumber()));
        
        PdfPCell toLabel = createCellNoBorder("To:", true);
        toLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(toLabel);
        table.addCell(createCellNoBorder(loadingsheet.getDestination().getName()));
        
        
        PdfPCell dateLabel = createCellNoBorder("Loadingsheet date:", true);
        dateLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(dateLabel);
        table.addCell(createCellNoBorder(app.formatDateWithoutTime(loadingsheet.getLoadDate())));
        
        PdfPCell status = createCellNoBorder("Status:", true);
        status.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(status);
        table.addCell(createCellNoBorder(loadingsheet.getLoadingsheetStatus().getDescription()));
        
        
        PdfPCell driverLabel = createCellNoBorder("Driver:", true);
        driverLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(driverLabel);
        Phrase driver = new Phrase(loadingsheet.getDriver().toString(), FontFactory.getFont(FontFactory.TIMES, 10, Font.UNDERLINE));
        table.addCell(createCellNoBorder(driver));
        
        PdfPCell conductorLabel = createCellNoBorder("Conductor:", true);
        conductorLabel.setHorizontalAlignment(Element.ALIGN_RIGHT);
        table.addCell(conductorLabel);
        Phrase conductor = new Phrase(loadingsheet.getConductor().toString(), FontFactory.getFont(FontFactory.TIMES, 10, Font.UNDERLINE));
        table.addCell(createCellNoBorder(conductor));
        
        return table;
    }
    
    /**
     * Creates loadingsheet parcels table
     * @return table withe the parcels for this loadingsheet
     */
    public static PdfPTable createLoadingsheetParcelsTable(ParcelApplication app, Loadingsheet loadingsheet, List<Parcel> parcels) {
        PdfPTable table = new PdfPTable(new float[] { 1, 2, 3, 2, 3, 2, 1, 2, 2});
        table.setWidthPercentage(100f);
        
        table.addCell(createCellWithBorderButtom("#", true));
        table.addCell(createCellWithBorderButtom("Waybill No", true));
        table.addCell(createCellWithBorderButtom("Sender", true));
        table.addCell(createCellWithBorderButtom("Sender tel", true));
        table.addCell(createCellWithBorderButtom("Receiver", true));
        table.addCell(createCellWithBorderButtom("Receiver tel", true));
        table.addCell(createCellWithBorderButtom("Qty", true));
        table.addCell(createCellWithBorderButtom("Type", true));
        table.addCell(createCellWithBorderButtom("Pay mode", true));
        
        String checkedBy = "Checked by: ";
        PdfPCell c1 = new PdfPCell(checkedBy);
        c1.setColspan(2);
        c1.setBorder(0);
        table.addCell(c1);
        String date = app.formatDateWithoutTime(new Date());
        String checkedDate= "Date: "+date;
        PdfPCell c2 = new PdfPCell(checkedDate);
        c2.setColspan(2);
        c2.setBorder(0);
        table.addCell(c2);
        String receivedBy = "Received by: "+loadingsheet.getConductor().toString();
        PdfPCell c3 = new PdfPCell(receivedBy);
        c3.setColspan(3);
        c3.setBorder(0);
        table.addCell(c3);
        table.addCell(c2);
        
        table.addCell(createCellNoBorder("Sign:"));
        table.addCell(createCellNoBorder(""));
        table.addCell(createCellNoBorder(""));
        table.addCell(createCellNoBorder(""));
        table.addCell(createCellNoBorder("Sign:"));
        table.addCell(createCellNoBorder(""));
        table.addCell(createCellNoBorder(""));
        table.addCell(createCellNoBorder(""));
        table.addCell(createCellNoBorder(""));
        
        String printedOn = "Printed on: "+ date;
        PdfPCell b1 = new PdfPCell(printedOn, 8);
        b1.setColspan(4);
        b1.setBorder(0);
        table.addCell(b1);
                
        String preparedBy = "Prepared by: "+ app.getUser().getEmployee().toString();
        PdfPCell b3 = new PdfPCell(preparedBy, 8);
        b3.setColspan(5);
        b3.setBorder(0);
        table.addCell(b3);
        
        table.setHeaderRows(4);
        table.setFooterRows(3);
        
        int i = 1;
        for (Parcel parcel : parcels) {
        	table.addCell(createCellWithBorderButtom(i+++""));
            table.addCell(createCellWithBorderButtom(parcel.getWaybillNumber()));
            table.addCell(createCellWithBorderButtom(parcel.getParcelDetail().getSenderName()));
            table.addCell(createCellWithBorderButtom(parcel.getParcelDetail().getSenderTel()));
            table.addCell(createCellWithBorderButtom(parcel.getParcelDetail().getReceiverName()));
            table.addCell(createCellWithBorderButtom(parcel.getParcelDetail().getReceiverTel()));
            PdfPCell quantity = createCellWithBorderButtom(parcel.getQuantity().toString());
            quantity.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.addCell(quantity);
            table.addCell(createCellWithBorderButtom(parcel.getParcelType().toString()));
            table.addCell(createCellWithBorderButtom(parcel.getPaymentMode().toString()));
		}
        return table;
    }
    
    private static PdfPCell createCellNoBorder(String text){
    	PdfPCell cell = new PdfPCell(text);
        cell.setBorder(0);
        return cell;
    }
    
    private static PdfPCell createCellNoBorder(String text, Boolean isBold){
    	PdfPCell cell = new PdfPCell(text, isBold);
        cell.setBorder(0);
        return cell;
    }
    
    private static PdfPCell createCellWithBorderButtom(String text){
    	PdfPCell cell = new PdfPCell(text);
        cell.setBorder(Rectangle.BOTTOM);
        return cell;
    }
    
    private static PdfPCell createCellWithBorderButtom(String text, Boolean isBold){
    	PdfPCell cell = new PdfPCell(text, isBold);
        cell.setBorder(Rectangle.BOTTOM);
        return cell;
    }
    
    private static PdfPCell createCellNoBorder(Phrase p){
    	PdfPCell cell = new PdfPCell(p);
        cell.setBorder(0);
        return cell;
    }
    
    private static PdfPCell createCellWithBorderLeft(String text){
    	PdfPCell cell = new PdfPCell(text);
        return createCellWithBorderLeft(cell);
    }
    
    private static PdfPCell createCellWithBorderLeft(String text, Boolean isBold){
    	PdfPCell cell = new PdfPCell(text, isBold);
        return createCellWithBorderLeft(cell);
    }
    
    private static PdfPCell createCellWithBorderLeft(PdfPCell cell){
        cell.setBorderWidthRight(0f);
        cell.setBorderWidthTop(0f);
        cell.setBorderWidthBottom(0f);
        return cell;
    }
    
    private static PdfPCell createCellWithBorderRight(String text){
    	PdfPCell cell = new PdfPCell(text);
        return createCellWithBorderRight(cell);
    }
    
    private static PdfPCell createCellWithBorderRight(String text, Boolean isBold){
    	PdfPCell cell = new PdfPCell(text, isBold);
        return createCellWithBorderRight(cell);
    }
    
    private static PdfPCell createCellWithBorderRight(String text, Boolean isBold, Boolean isUnderline){
    	PdfPCell cell = new PdfPCell(text, isBold, isUnderline);
        return createCellWithBorderRight(cell);
    }
    
    private static PdfPCell createCellWithBorderRight(PdfPCell cell){
        cell.setBorderWidthLeft(0f);
        cell.setBorderWidthTop(0f);
        cell.setBorderWidthBottom(0f);
        return cell;
    }
    
    private static PdfPCell createCellWithoutBorderRightLeft(String text){
    	PdfPCell cell = new PdfPCell(text);
        return createCellWithoutBorderRightLeft(cell);
    }
    
    private static PdfPCell createCellWithoutBorderRightLeft(String text, Boolean isBold){
    	PdfPCell cell = new PdfPCell(text, isBold);
        return createCellWithoutBorderRightLeft(cell);
    }
    
    private static PdfPCell createCellWithoutBorderRightLeft(PdfPCell cell){
        cell.setBorderWidthRight(0f);
        cell.setBorderWidthLeft(0f);
        return cell;
    }
    
    private static PdfPCell createCellWithBorderRightAndButtom(String text){
    	PdfPCell cell = new PdfPCell(text, 8);
        cell.setBorderWidthTop(0f);
        cell.setBorderWidthLeft(0f);
        return cell;
    }
    
    private static PdfPCell createCellWithBorderLeftAndButtom(String text){
    	PdfPCell cell = new PdfPCell(text, 8);
        cell.setBorderWidthRight(0f);
        cell.setBorderWidthTop(0f);
        return cell;
    }
}
